// Package object: 对象包，定义了各种数据对象类型，并都实现了对象接口。比如: int类型，bool类型...
package object

import (
	"bytes"
	"fmt"
	"hash/fnv"
	"strings"
	"z-lang/ast"
	"z-lang/code"
)

// ObjectType 数据类型
type ObjectType string

// BuiltinFunction 内置函数类型
type BuiltinFunction func(args ...Object) Object

const (
	IntegerObj          = "INTEGER"           // int 类型
	BooleanObj          = "BOOLEAN"           // bool 类型
	NullObj             = "NULL"              // null 类型
	ReturnValueObj      = "RETURN_VALUE"      // return 类型
	ErrorObj            = "ERROR"             // error 类型 - 主要是指程序内部的错误处理流程.比如: 错误的运算符、不支持的操作以及执行期间发生的其他错误或者内部错误
	FunctionObj         = "FUNCTION"          // 函数对象类型
	StringObj           = "STRING"            // 字符串类型
	BuiltinObj          = "BUILTIN"           // 内置函数类型
	ArrayObj            = "ARRAY"             // 数组类型
	TupleObj            = "TUPLE"             // 元组类型
	HashObj             = "HASH"              // 哈希表类型
	EmptyObj            = "EMPTY"             // 空类型 - 表示什么都不用做，内部使用
	CompiledFunctionObj = "COMPILED_FUNCTION" // 编译成字节码之后的函数对象
	ClosureObj          = "CLOSURE"           // 闭包类型
)

// Object 数据信息接口。采取最简单的方式, 对于求值的返回值统一用Object表示
type Object interface {
	Type() ObjectType // 获取数据的类型
	Inspect() string  // 获取数据值
}

// Hashable 哈希码生成接口。
type Hashable interface {
	HashKey() HashKey
}

// HashKey 哈希码生成结构体
type HashKey struct {
	Type  ObjectType // 数据类型, 表示这个HashKey可以用于哪个对象类型
	Value uint64     // 实际的哈希值
}

type Empty struct{}

// Type Empty实现Object接口的Type方法, 返回 EmptyObj
func (e *Empty) Type() ObjectType {
	return EmptyObj
}

// Inspect Empty实现Object接口的Inspect方法，返回 ""
func (e *Empty) Inspect() string {
	return ""
}

// Integer int类型数据
type Integer struct {
	Value int64
}

// Type Integer实现Object接口的Type方法, 返回 IntegerObj
func (it *Integer) Type() ObjectType {
	return IntegerObj
}

// Inspect Integer实现Object接口的Inspect方法，返回 Integer.Value
func (it *Integer) Inspect() string {
	return fmt.Sprintf("%d", it.Value)
}

// HashKey Integer实现HashKey方法，返回一个HashKey对象
func (it *Integer) HashKey() HashKey {
	return HashKey{Type: it.Type(), Value: uint64(it.Value)}
}

// Boolean bool类型数据
type Boolean struct {
	Value bool
}

// Type Boolean实现Object接口的Type方法, 返回 BooleanObj
func (bl *Boolean) Type() ObjectType {
	return BooleanObj
}

// Inspect Boolean实现Object接口的Inspect方法，返回 Boolean.Value
func (bl *Boolean) Inspect() string {
	return fmt.Sprintf("%t", bl.Value)
}

// HashKey Boolean实现HashKey方法，返回一个HashKey对象
func (bl *Boolean) HashKey() HashKey {
	var val uint64
	if bl.Value {
		val = 1
	} else {
		val = 0
	}
	return HashKey{Type: bl.Type(), Value: val}
}

// Null null类型
type Null struct{}

// Type Null实现Object接口的Type方法, 返回 NullObj
func (bl *Null) Type() ObjectType {
	return NullObj
}

// Inspect Null实现Object接口的Inspect方法，返回 null
func (bl *Null) Inspect() string {
	return fmt.Sprint("null")
}

// ReturnValue 返回值类型
type ReturnValue struct {
	Value Object
}

// Type ReturnValue实现Object接口的Type方法, 返回 RETURN_VALUE_OBJ
func (rv *ReturnValue) Type() ObjectType {
	return ReturnValueObj
}

// Inspect ReturnValue实现Object接口的Inspect方法，返回 ReturnValue.Value.Inspect()
func (rv *ReturnValue) Inspect() string {
	return rv.Value.Inspect()
}

// Error 错误类型. 主要是指程序内部的错误处理流程.比如: 错误的运算符、不支持的操作以及执行期间发生的其他错误或者内部错误
type Error struct {
	Message string // 错误信息
}

// Type Error实现Object接口的Type方法, 返回 ErrorObj
func (e *Error) Type() ObjectType {
	return ErrorObj
}

// Inspect Error实现Object接口的Inspect方法，返回错误信息
func (e *Error) Inspect() string {
	return "Error: " + e.Message
}

// CompiledFunction 编译成字节码之后的函数对象
//
//	CompiledFunction 用来保存编译之后的函数的指令，并将它们以常量的形式作为字节码的一部分从编译器传递给虚拟机。
//	OpCall 用来让虚拟机开始执行位于栈顶部的 CompiledFunction
//	OpReturnValue 用来让虚拟机将栈顶的值返回到调用上下文并在此恢复执行。
//	OpReturn，与 OpReturnValue 类似，不同之处在于没有显式返回值，而是隐式返回 vm.Null
type CompiledFunction struct {
	Instructions  code.Instructions // 函数对象的字节码
	NumLocals     int               // 方法的局部变量数
	NumParameters int               // 方法的参数数量
}

// Type CompiledFunction 实现 Object 接口的 Type 方法，返回 CompiledFunctionObj
func (c *CompiledFunction) Type() ObjectType {
	return CompiledFunctionObj
}

// Inspect CompiledFunction 实现 Object 接口的 Inspect 方法
func (c *CompiledFunction) Inspect() string {
	return fmt.Sprintf("CompiledFunction[%p]", c.Instructions)
}

// Function 函数对象
type Function struct {
	Parameters []*ast.Identifier   // 参数列表
	Body       *ast.BlockStatement // 函数体
	Env        *Environment        // 函数上下文
}

// Type Function实现Object接口的Type方法, 返回 FunctionObj
func (f *Function) Type() ObjectType {
	return FunctionObj
}

// Inspect Function实现Object接口的Inspect方法，返回函数信息 fn(参数列表) { 语句块 }
func (f *Function) Inspect() string {
	var out bytes.Buffer

	var p []string
	for _, pr := range f.Parameters {
		p = append(p, pr.String())
	}

	out.WriteString("fn")
	out.WriteString("(")
	out.WriteString(strings.Join(p, ", "))
	out.WriteString(") {\n")
	out.WriteString(f.Body.String())
	out.WriteString("\n}")

	return out.String()
}

// String 字符串类型
type String struct {
	Value string // 字符串值
}

// Type String实现Object接口的Type方法，返回 StringObj
func (s *String) Type() ObjectType {
	return StringObj
}

// Inspect String实现Object接口的Inspect方法
func (s *String) Inspect() string {
	return s.Value
}

// HashKey String实现HashKey方法，返回一个HashKey对象
func (s *String) HashKey() HashKey {
	h := fnv.New64a()
	_, _ = h.Write([]byte(s.Value))

	return HashKey{Type: s.Type(), Value: h.Sum64()}
}

// Builtin 内置函数结构体定义
type Builtin struct {
	Fn BuiltinFunction
}

// Type Builtin实现Object接口的Type方法，返回 BuiltinObj
func (b *Builtin) Type() ObjectType {
	return BuiltinObj
}

// Inspect Builtin实现Object接口的Inspect方法, 直接返回 "builtin function"
func (b *Builtin) Inspect() string {
	return "builtin function"
}

// Array 数组结构体
type Array struct {
	Elements []Object // 数组元素
}

// Type Array实现Object接口的Type方法，返回 ArrayObj
func (a *Array) Type() ObjectType {
	return ArrayObj
}

// Inspect Array实现Object接口的Inspect方法, 返回 [元素1, 元素2, ...]
func (a *Array) Inspect() string {
	var out bytes.Buffer

	var es []string
	for _, e := range a.Elements {
		es = append(es, e.Inspect())
	}

	out.WriteString("[")
	out.WriteString(strings.Join(es, ", "))
	out.WriteString("]")

	return out.String()
}

// Tuple 元组结构体 - 2023/6/25
// 初始化之后就不能变，不允许修改元组内的元素，但是可以获取，查看元组内部的元素
type Tuple struct {
	Elements []Object // 元组元素
}

// Type Tuple实现Object接口
func (t *Tuple) Type() ObjectType {
	return TupleObj
}

// Inspect Tuple实现Object接口的Inspect方法, 返回 [元素1, 元素2, ...]
func (t *Tuple) Inspect() string {
	var out bytes.Buffer

	var es []string
	for _, e := range t.Elements {
		es = append(es, e.Inspect())
	}

	out.WriteString("(")
	out.WriteString(strings.Join(es, ", "))
	out.WriteString(")")

	return out.String()
}

// HashPair 键值对结构体
type HashPair struct {
	Key   Object
	Value Object
}

// Hash 哈希表
type Hash struct {
	Pairs map[HashKey]HashPair // 键值对
}

// Type Hash实现Object接口的Type方法，返回 HashObj
func (h *Hash) Type() ObjectType {
	return HashObj
}

// Inspect Hash实现Object接口的Inspect方法,
func (h *Hash) Inspect() string {
	var out bytes.Buffer

	var pairs []string
	for _, v := range h.Pairs {
		pairs = append(pairs, fmt.Sprintf("%s: %s", v.Key.Inspect(), v.Value.Inspect()))
	}

	out.WriteString("{")
	out.WriteString(strings.Join(pairs, ", "))
	out.WriteString("}")

	return out.String()
}

// Environment 用来存储 标识符与其值的映射
type Environment struct {
	store map[string]Object // 储存 标识符与值 的映射
	outer *Environment      // 外层环境
}

// NewEnvironment 创造一个Environment指针
func NewEnvironment() *Environment {
	s := make(map[string]Object)
	return &Environment{store: s}
}

func NewEnclosedEnv(outer *Environment) *Environment {
	env := NewEnvironment()
	env.outer = outer
	return env
}

func (e *Environment) Get(name string) (Object, bool) {
	obj, ok := e.store[name]
	if !ok && e.outer != nil {
		obj, ok = e.outer.Get(name)
	}
	return obj, ok
}

func (e *Environment) Set(name string, obj Object) Object {
	e.store[name] = obj
	return obj
}

// Closure 闭包类型结构体
type Closure struct {
	Fn   *CompiledFunction // 闭包函数
	Free []Object          // 自由变量 - 既不是在当前局部作用域中定义的变量，也不是当前函数的参数。由于不受当前作用域的约束，因此它们是自由的
}

func (c *Closure) Type() ObjectType {
	return ClosureObj
}

func (c *Closure) Inspect() string {
	return fmt.Sprintf("Closure[%p]", c)
}
